/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package distFileSystem;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author 6766371
 */
public class Client implements Runnable {

    private static int op;
    private static String serv;
    private static int servPorta;
    private Socket conMestre;    //socket de comunicacao com o Mestre
    private InputStream in;      //stream para envia dados
    private OutputStream out;    //stream para receber dados
    //Variáveis para tratar erros
    private final static int FALHA = 0;
    private final static int SUCESSO = 1;
    private final static int ARQEXISTENTE = 2;      //arquivo que está tentando ser criado já existe
    private final static int UKERRO = 3;            //erro desconhecido
    private final static int SERVERNOTFOUND = 4;

    public static void main(String[] args) {
        Client cliente = new Client(args[0], Integer.parseInt(args[1]));

        while (true) {
            cliente.run();
        }
    }

    private Client(String servidor, int servidorPorta) {
        serv = servidor;
        servPorta = servidorPorta;
    }

    public String getServidor() {
        return serv;
    }

    public void setServidor(String servidor) {
        Client.serv = servidor;
    }

    public int getServPorta() {
        return servPorta;
    }

    public void setServPorta(int servPorta) {
        Client.servPorta = servPorta;
    }

    public int copiarArquivo(String nomeArq) throws IOException {

        try {
            conMestre = new Socket(serv, servPorta);    //cria a socket para estabelecer conexão com o servidor

            System.out.println("Conectando ao mestre... enviando a mensagem");

            in = conMestre.getInputStream();          //stream para receber a resposta do servidor
            out = conMestre.getOutputStream();       //stream para enviar a mensagem ao servidor
        } catch (IOException ex) {
            System.out.println("Falha: " + ex.getMessage());
            return FALHA;
        }
        PrintStream envio = new PrintStream(out);

        //envia primeiro a opcao
        envio.println("1");
        envio.flush();

        //envia o nome do arquivo
        envio.println(nomeArq);
        envio.flush();

        //Espera para receber a resposta do mestre
        Scanner scan = new Scanner(in);
        String respostaEnd = new String();     //auxiliar só para teste
        int respostaTam = 0;                   //auxiliar só para teste

        if (scan.hasNext()) {
            respostaEnd = scan.nextLine();
        }
        if (scan.hasNext()) {
            respostaTam = Integer.parseInt(scan.nextLine());
        }

        System.out.println("endereco: " + respostaEnd + "   tamanho: " + respostaTam);

        in.close();
        out.close();
        conMestre.close();
        envio.close();

        //comunica com o no que possui o arquivo
        File arq1 = new File("/opt/grupo08/Copy_" + nomeArq);
        FileOutputStream grava = new FileOutputStream(arq1);
        byte[] buff = new byte[respostaTam];
        Socket comunica = new Socket(respostaEnd, servPorta);
        in = comunica.getInputStream();
        out = comunica.getOutputStream();
        PrintStream envio2 = new PrintStream(out);

        //envia o código que informa que é comunicação para cópia de arquivo
        envio2.println("1");
        //envia o nome do arquivo para o nó que possui o arquivo
        envio2.println(nomeArq);
        envio2.flush();

        System.out.println("Nome arquivo copia: " + nomeArq + "_copy.txt ......e Copiando arquivo");
        while ((in.read(buff, 0, respostaTam)) != -1) {
            grava.write(buff, 0, respostaTam);
        }

        grava.flush();
        grava.close();
        comunica.close();
        in.close();
        out.close();
        envio.close();
        return SUCESSO;
        //fim caso cliente
    }

    public int excluirArquivo(String nomeArq) throws IOException {
        try {
            conMestre = new Socket(serv, servPorta);    //cria a socket para estabelecer conexão com o servidor

            System.out.println("Conectando ao mestre... enviando a mensagem");

            in = conMestre.getInputStream();          //stream para receber a resposta do servidor
            out = conMestre.getOutputStream();       //stream para enviar a mensagem ao servidor
        } catch (IOException ex) {
            System.out.println("Falha: " + ex.getMessage());
            return FALHA;
        }

        PrintStream envio = new PrintStream(out);

        //envia primeiro a opcao
        envio.println("2");
        envio.flush();

        //envia o nome do arquivo
        envio.println(nomeArq);
        envio.flush();

        //Espera para receber a resposta do servidor
        Scanner scan = new Scanner(in);
        int respostaMestre = FALHA;       //arquivo não existe(FALHA) ou arquivo excluído(SUCESSO)

        if (scan.hasNext()) {
            respostaMestre = Integer.parseInt(scan.nextLine());
        }
        System.out.println("Status da resposta do Mestre: " + respostaMestre);
        if (respostaMestre == FALHA) {
            return respostaMestre;
        } else if (respostaMestre == SUCESSO) {
            return respostaMestre;
        } else {
            return UKERRO;
        }
    }

    public int criaArquivo(String nomeArq) throws IOException {        //retorno: 0(falha), 1(sucesso), 2(arquivo já existe), 3(ERRO!), 4(Servidor não encontrado)

        try {
            conMestre = new Socket(serv, servPorta);    //cria a socket para estabelecer conexão com o servidor

            System.out.println("Conectando ao mestre... enviando a mensagem");

            in = conMestre.getInputStream();          //stream para receber a resposta do servidor
            out = conMestre.getOutputStream();       //stream para enviar a mensagem ao servidor
        } catch (UnknownHostException ex) {
            return SERVERNOTFOUND;
        }

        PrintStream envio = new PrintStream(out);

        //envia primeiro a opcao
        envio.println("3");
        envio.flush();

        //envia o nome do arquivo
        envio.println(nomeArq);
        envio.flush();

        //Espera para receber a resposta do servidor
        Scanner scan = new Scanner(in);
        int respostaMestre = FALHA;       //arquivo já existe(ARQEXISTENTE) ou permitido para criar(SUCESSO)

        if (scan.hasNext()) {
            respostaMestre = Integer.parseInt(scan.nextLine());
        }


        if (respostaMestre == FALHA) {
            return respostaMestre;
        } else if (respostaMestre == SUCESSO) {
            try {
                File arq = new File("/opt/grupo08/" + nomeArq);
                arq.createNewFile();                                            //Arquivo criado
                System.out.println("Conteudo do arquivo: ");
                InputStreamReader teclado = new InputStreamReader(System.in);   //ler do teclado o conteúdo q terá o arquivo
                BufferedReader br = new BufferedReader(teclado);
                FileWriter fw = new FileWriter(arq);
                BufferedWriter bw = new BufferedWriter(fw);
                bw.write(br.readLine());
                bw.flush();
                bw.close();

                //envio dos dados para serem cadastrados no BD
                //tamanho arquivo
                envio.println(String.valueOf(arq.length()));
                //nome do nó
                envio.println(InetAddress.getLocalHost().getHostName());
            } catch (IOException e) {
                return ARQEXISTENTE;
            }

            return respostaMestre;
        } else if (respostaMestre == ARQEXISTENTE) {
            return respostaMestre;
        }
        return UKERRO;
    }

    public void criar(BufferedReader br) throws IOException {
        String nArq;
        String entrada;                 //em caso de arquivo já existente a reopção é recebida por essa variável
        int statusCria = FALHA;


        System.out.println("Nome do arquivo: ");
        while (statusCria != SUCESSO) {
            nArq = br.readLine();
            statusCria = criaArquivo(nArq);

            switch (statusCria) {
                case SUCESSO:
                    System.out.println("Arquivo '" + nArq + "' criado com sucesso.");
                    break;
                case FALHA:
                    System.out.println("Falha no sistema. Digite o nome do arquivo novamente: ");
                    break;
                case ARQEXISTENTE:
                    System.out.println("Arquivo existente:\n"
                            + "(1) Criar arquivo novamente com outro nome\n"
                            + "(2) Copiar o arquivo existente");          //verificar se cliente deseja ler o arquivo existente
                    entrada = br.readLine();
                    //implementar o que o cliente escolheu
                    if (entrada.equalsIgnoreCase("1")) {
                        statusCria = FALHA;
                        break;
                    } else if (entrada.equalsIgnoreCase("2")) {
                        ler(br);
                        statusCria = SUCESSO;
                        break;
                    }
                case UKERRO:
                    System.out.println("Erro!\n Digite o nome do arquivo novamente: ");
                    break;
                case SERVERNOTFOUND:
                    System.out.println("Servidor nao encontrado. Redefina o servidor.");
                    break;
            }
        }
    }

    public void excluir(BufferedReader br) throws IOException {
        String nArq;
        int index = -1;
        int statusExcluir = FALHA;


        System.out.println("Arquivo buscado: ");

        while (statusExcluir != SUCESSO) {
            nArq = br.readLine();
            statusExcluir = excluirArquivo(nArq);

            switch (statusExcluir) {
                case SUCESSO:
//                    files.remove(nArq);
                    break;
                case FALHA:
                    System.out.println("Arquivo inexistente. Digite o nome do arquivo novamente: ");
                    break;
                case ARQEXISTENTE:
                    statusExcluir = SUCESSO;
                    break;
                //implementar o q o cliente escolheu
                case UKERRO:
                    System.out.println("Erro!\n Digite o nome do arquivo novamente: ");
                    break;
                case SERVERNOTFOUND:
                    System.out.println("Servidor nao encontrado. Redefina o servidor.");
                    break;
            }
        }
    }

    public void ler(BufferedReader br) throws IOException {
        String nArq;

        System.out.println("Arquivo buscado: ");
        nArq = br.readLine();
        copiarArquivo(nArq);                //realiza a operacao do cliente, requisicao de arquivo
    }

    @Override
    public void run() {
        while (true) {
            try {
                System.out.println("Digite a operacao desejada: \n"
                        + "(1) Ler\n"
                        + "(2) Excluir\n"
                        + "(3) Criar\n");

                //lê do teclado a operação desejada pelo usuário
                InputStreamReader in = new InputStreamReader(System.in);
                BufferedReader br = new BufferedReader(in);

                String entrada = new String();
                do {

                    entrada = br.readLine();

                } while (((entrada.compareTo("1")) != 0) && ((entrada.compareTo("2")) != 0) && ((entrada.compareTo("3")) != 0));

                op = Integer.parseInt(entrada);
                if (op == 1) {                 //se o no quiser requisitar um arquivo
                    ler(br);
                } else if (op == 2) {                     // se o nó tiver que enviar um arquivo
                    excluir(br);
                } else if (op == 3) {                     // se o nó tiver que enviar um arquivo
                    criar(br);
                }

            } catch (IOException ex) {
                Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}
